package com.higgins.client.components;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.SelectElement;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HTMLTable.Cell;
import com.higgins.client.GreetingService;
import com.higgins.client.GreetingServiceAsync;
import com.higgins.client.dataModel.CoveringLetterDTO;
import com.higgins.client.dataModel.RecipientCountDTO;
import com.higgins.client.dataModel.StatusDTO;
import com.higgins.client.dataModel.StrategyDTO;
import com.higgins.client.dataModel.StrategyRecipientCountDTO;
import com.higgins.client.dataModel.StrategyRecipientDTO;
import com.higgins.client.generic.components.GenericColumn;
import com.higgins.client.generic.components.GenericTable;

public class StrategyTable extends GenericTable	{
	private static final Logger log = Logger.getLogger(StrategyTable.class.getName());
	private final GreetingServiceAsync greetingService = GWT
			.create(GreetingService.class);
	
	public StrategyTable(StrategyColumns columns)	{
		super(columns);
		retrieveDTOs();
	}
	
	protected void addObject(int row, int column, Object object)	{
		ensureRowAvailable(row);
		GenericColumn genericColumn = genericColumns.getColumn(column);
		if (genericColumn.getType().equals(StatusDTO.class))	{
			addStatusDTO(row, column, object, genericColumn);
		}	else if (genericColumn.getType().equals(CoveringLetterDTO.class))	{
			addCoveringLetterDTO(row, column, object, genericColumn);
		} 	else if (genericColumn.getType().equals(RecipientCountDTO.class))	{
			addRecipientCountDTO(row, column, object, genericColumn);
		} 
	}
	protected void addCoveringLetterDTO(int row, int column, Object object, GenericColumn genericColumn)	{
		final ListBox listBox = new ListBox();
		final int finalRow = row; 
		int count = 1;
		listBox.addItem("");
		List<Object> list = genericColumn!=null?genericColumn.getList():new ArrayList<Object>();
		for (Object listItem:(list!=null?list:new ArrayList<Object>()))	{
			String item = ((CoveringLetterDTO)listItem).getName();
			listBox.addItem(item);
			if (((String)object).equals(item))	{
				listBox.setSelectedIndex(count);
			}
			count++;
		}
		listBox.addChangeHandler(new ChangeHandler() {
	        public void onChange(ChangeEvent changeEvent) {
	            SelectElement selectElement = listBox.getElement().cast();
	            selectElement.getOptions().getItem(0).setDisabled(true);
	            updateItemCell(finalRow);

	        }
	    });
		setWidget(row, column, listBox);
 		getCellFormatter().addStyleName(row, column, "FlexTable-normCell");		
	}
	protected void addStatusDTO(int row, int column, Object object, GenericColumn genericColumn)	{
		if (object.equals("None") || object.equals("Requested"))	{
			Button button = new Button();
			if (object.equals("None"))
				button.setText("Publish");
			else
				button.setText("Un-Publish");
			button.addClickHandler(new ClickHandler()  {
				@Override
				public void onClick(ClickEvent event) {
					publish(event);
				}  });
			setWidget(row, column, button);
		} else {
			setText(row, column, object.toString());
		}
 		getCellFormatter().addStyleName(row, column, "FlexTable-normCell");		
	}
	protected void addRecipientCountDTO(int row, int column, Object object, GenericColumn genericColumn)	{
		setText(row, column, object.toString());
 		getCellFormatter().addStyleName(row, column, "FlexTable-normCell");		
	}
	
	private List<List<Object>> convertDTOtoRowArray(List<StrategyDTO> strategyDTOs)	{
		List<List<Object>> rows = new ArrayList<List<Object>>();
		for (StrategyDTO strategyDTO:strategyDTOs)	{
			List<Object> row = new ArrayList<Object>();
			row.add(strategyDTO.getId());
			row.add(strategyDTO.getName());
			row.add(strategyDTO.getCoveringLetterDTO()!=null?strategyDTO.getCoveringLetterDTO().getName():"");
			row.add(statusField(strategyDTO));
			row.add("");
			rows.add(row);
		}
		return rows;
	}
	
	public void updateItemCell(int row)	{
		StrategyDTO strategyDTO = new StrategyDTO();
		strategyDTO.setId(getId(row));
		strategyDTO.setName(getText(row, 1));
		strategyDTO.setCoveringLetterDTO(getCoveringLetterDTO(row, 2));
		updateRow(strategyDTO);
	}
	
	protected void retrieveDTOs()	{
		try {
			greetingService.retrieveStrategys(new AsyncCallback<List<StrategyDTO>>()	{
					@Override
					public void onFailure(Throwable caught) {
						log.info("FixedOutgoingDTO: " + caught.toString());
					}

					@Override
					public void onSuccess(List<StrategyDTO> result) {
						loadData(convertDTOtoRowArray(result));
						retrieveRecipientCounts(result);
					}
				});
		} catch (IllegalArgumentException e) {
			log.info("FixedOutgoingDTO: " + e.toString());
		} /*catch (SecurityAccessDeniedException e) {
			log.info("SecurityAccessDeniedException: " + e.toString());
		} */
	}	
	private void retrieveRecipientCounts(List<StrategyDTO> results)		{
		for (StrategyDTO dto:results)	{
			try {
				greetingService.retrieveStrategyRecipientCount(dto.getId(), new AsyncCallback<StrategyRecipientCountDTO>()	{
						@Override
						public void onFailure(Throwable caught) {
							log.info("FixedOutgoingDTO: " + caught.toString());
						}
	
						@Override
						public void onSuccess(StrategyRecipientCountDTO result) {
							setRecipientCount(result);
						}
					});
			} catch (IllegalArgumentException e) {
				log.info("FixedOutgoingDTO: " + e.toString());
			} 
		}
	}
	private void setRecipientCount(StrategyRecipientCountDTO dto)	{
		int column = getRecipientCountColumn();
		int rows = getRowCount();
		for (int row = 1; row < rows; row++)	{
			Long strategyId = getId(row);
			if (strategyId!=null && dto.getStrategyId().equals(strategyId))	{
				setText(row, column, dto.getRecipientCount().toString());
			} 
		}
	}
	
	private void updateRow(StrategyDTO strategyDTO)	{
		try {
			greetingService.updateStrategy(strategyDTO, new AsyncCallback<String>()	{
					@Override
					public void onFailure(Throwable caught) {
						log.info("FixedOutgoingDTO: " + caught.toString());
					}

					@Override
					public void onSuccess(String result) {
						setRowIdAfterUpdate(result);
					}
				});
		} catch (IllegalArgumentException e) {
			log.info("FixedOutgoingDTO: " + e.toString());
		} /*catch (SecurityAccessDeniedException e) {
			log.info("SecurityAccessDeniedException: " + e.toString());
		} 		*/
	}
	
	public CoveringLetterDTO getCoveringLetterDTO(int row, int column)	{
		try	{
			ListBox listBox = (ListBox)getWidget(row, column);
			int selectedIndex = listBox.getSelectedIndex();
			String coveringLetter = listBox.getItemText(selectedIndex);
			return getCoveringLetterDTO(coveringLetter);
		} catch (Exception e)	{
			return null;
		}
	}
	@SuppressWarnings("unchecked")
	public CoveringLetterDTO getCoveringLetterDTO(String string)	{
		for (GenericColumn genericColumn:genericColumns.getColumns())	{
			if (genericColumn.getType()==(CoveringLetterDTO.class))	{
				if (genericColumn.getList()!=null)	{
					for (CoveringLetterDTO dto:(List<CoveringLetterDTO>)genericColumn.getList())	{
						if (dto.getName().equals(string))	{
							return dto;
						}
					}
				}
			}
		}
		return null;
	}
	protected String statusField(StrategyDTO dto)	{
		if (dto.getStatus()==null)	{
			dto.setStatus(0);
		}
		Integer status = dto.getStatus();
		if (status!=null)	{
			switch (status)	{
			case 0:
				return "None";
			case 1:
				return "Requested";
			case 2:
				return "Generated";
			case 3:
				return "Posted";
			}
		} 
		return "";
	}
	protected Integer getStatusColumn()	{
		for(GenericColumn genericColumn:genericColumns.getColumns())	{
			if (genericColumn.getType().equals(StatusDTO.class))
				return genericColumn.getIndex();
		}
		return null;
	}
	protected Integer getRecipientCountColumn()	{
		for(GenericColumn genericColumn:genericColumns.getColumns())	{
			if (genericColumn.getType().equals(RecipientCountDTO.class))
				return genericColumn.getIndex();
		}
		return null;
	}
	private void publish(ClickEvent event)	{
		Cell cell = getCellForEvent(event);
		final int row = cell.getRowIndex();
		final int column = cell.getCellIndex();
		CheckBox checkBox = (CheckBox)getWidget(row, 0);
		Button button = (Button)getWidget(row, column);
		String strategyId = checkBox.getName();
		if (button.getText().equals("Publish"))	{
			publish(strategyId);
		} else {
			unpublish(strategyId);
		}
	}
	private void publish(String strategyId)	{
		try	{
			Long id = Long.parseLong(strategyId);
			greetingService.publishStrategy(id, new AsyncCallback<String>()  {
				@Override
				public void onFailure(Throwable caught) {
				}
				@Override
				public void onSuccess(String result) {
					setButtonText(result, "Un-Publish");
				}  });
		} catch (Exception e)	{
			
		}
	}
	private void unpublish(String strategyId)	{
		try	{
			Long id = Long.parseLong(strategyId);
			greetingService.unpublishStrategy(id, new AsyncCallback<String>()  {
				@Override
				public void onFailure(Throwable caught) {
				}
				@Override
				public void onSuccess(String result) {
					setButtonText(result, "Publish");
				}  });
		} catch (Exception e)	{
			
		}
	}	
	private void setButtonText(String strategyId, String text)	{
		Long id = Long.parseLong(strategyId);
		Integer row = getRow(id);
		int column = getStatusColumn();
		Button button = (Button)getWidget(row, column);
		button.setText(text);
	}
}